From 10a7a89311ba0edf93c70470ddac23ecf2d8c3e7 Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Sat, 22 Nov 2014 09:07:51 -0800 Subject: [PATCH] gdkinternals: Document our drawing and painting process better --- gdk/gdkinternals.h | 77 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 5 deletions(-) diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h index 67a58da1fb..cbb87e44a2 100644 --- a/gdk/gdkinternals.h +++ b/gdk/gdkinternals.h @@ -216,15 +216,82 @@ struct _GdkWindow cairo_pattern_t *background; + /* The paint logic here is a bit complex because of our intermingling of + * cairo and GL. Let's first go over the cairo-alone case: + * + * 1) gdk_window_begin_paint_region() is called with an update region. If + * the backend wants it, we redirect drawing to a temporary surface + * sized the same as the update region and set `surface_needs_composite` + * to TRUE. Otherwise, we paint directly onto the real server-side window. + * + * 2) Things paint with cairo using gdk_cairo_create(). + * + * 3) When everything is painted, the user calls gdk_window_end_paint(). + * If there was a temporary surface, this is composited back onto the + * real backing surface in the appropriate places. + * + * This is similar to double buffering, except we only have partial surfaces + * of undefined contents, and instead of swapping between two buffers, we + * create a new temporary buffer every time. + * + * When we add GL to the mix, we have this instead: + * + * 1) gdk_window_begin_paint_region() is called with an update region like + * before. We always redirect cairo drawing to a temporary surface when + * GL is enabled. + * + * 2) Things paint with cairo using gdk_cairo_create(). Whenever + * something paints, it calls gdk_window_mark_paint_from_clip() to mark + * which regions it has painted in software. We'll learn what this does + * soon. + * + * 3) Something paints with GL and uses gdk_cairo_draw_from_gl() to + * composite back into the scene. We paint this onto the backing + * store for the window *immediately* by using GL, rather than + * painting to the temporary surface, and keep track of the area that + * we've painted in `flushed_region`. + * + * 4) Something paints using software again. It calls + * gdk_window_mark_paint_from_clip(), which subtracts the region it + * has painted from `flushed_region` and adds the region to + * `needs_blended_region`. + * + * 5) Something paints using GL again, using gdk_cairo_draw_from_gl(). + * It paints directly to the backing store, removes the region it + * painted from `needs_blended_region`, and adds to `flushed_region`. + * + * 6) gdk_window_end_paint() is called. It composites the temporary surface + * back to the window, using GL, except it doesn't bother copying + * `flushed_region`, and when it paints `needs_blended_region`, it also + * turns on GL blending. + * + * That means that at any point in time, we have three regions: + * + * * `region` - This is the original invalidated region and is never + * touched. + * + * * `flushed_region` - This is the portion of `region` that has GL + * contents that have been painted directly to the window, and + * doesn't have any cairo drawing painted over it. + * + * * `needs_blended_region` - This is the portion of `region` that + * GL contents that have part cairo drawing painted over it. + * gdk_window_end_paint() will draw this region using blending. + * + * `flushed_region` and `needs_blended_region` never intersect, and the + * rest of `region` that isn't covered by either is the "opaque region", + * which is any area of cairo drawing that didn't ever intersect with GL. + * We can paint these from GL without turning on blending. + **/ + struct { - cairo_region_t *region; + /* The temporary surface that we're painting to. This will be composited + * back into the window when we call end_paint. This is our poor-man's + * way of doing double buffering. */ cairo_surface_t *surface; - /* Areas of region that have been copied to the back buffer already */ + cairo_region_t *region; cairo_region_t *flushed_region; - /* Areas of region that have been copied to the back buffer but - needs furter blending of surface data. These two regions are - always non-intersecting. */ cairo_region_t *need_blend_region; gboolean surface_needs_composite; -- 2.30.2